#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include "stm32mp157_rcc.h"
#include "stm32mp157_gpio.h"
#include <linux/moduleparam.h>

struct stm32mp157_led{
	unsigned int major;
	struct class * clazz;
	struct device * dev;
	rcc_t * rcc;
	gpio_t * gpioz;
	gpio_t * gpioe;
	gpio_t * gpiof;
};

struct stm32mp157_led * led;

ssize_t led_drv_write(struct file * filp, const char __user * buff, size_t size, loff_t * pos)
{
	int ret;
	int led_cmd;
	//把用户空间的数据拷贝到内核空间(内核空间不能直接访问用户空间)
	//返回值>0: 没有拷贝成功的个数，失败！
	ret = copy_from_user(&led_cmd, buff, size);
	if(ret > 0)
	{
		printk("copy_from_user error\n");
		return -EAGAIN;
	}
	if(led_cmd == 1)
	{
		led->gpioz->ODR |= (0x01 << 5) | (0x01 << 6) | (0x01 << 7);
		led->gpioe->ODR |= (0x01 << 8) | (0x01 << 10);
		led->gpioe->ODR |= (0x01 << 10);
	}
	else
	{
		led->gpioz->ODR &= ~((0x01 << 5) | (0x01 << 6) | (0x01 << 7));
		led->gpioe->ODR &= ~((0x01 << 8) | (0x01 << 10));
		led->gpioe->ODR &= ~(0x01 << 10);
	}
	return 0;
}
	
int led_drv_open(struct inode * node, struct file * filp)
{
	printk("----------%s----------\n",__FUNCTION__);
	return 0;
}
	
int led_drv_release(struct inode * node, struct file * filp)
{
	printk("----------%s----------\n",__FUNCTION__);
	return 0;
}

const struct file_operations led_fops = {
	.write = led_drv_write,
	.open = led_drv_open,
	.release = led_drv_release,
};

static int a=0;

module_param(a,int,S_IRUGO);
MODULE_PARM_DESC(a,"e.g:str=hello");

static int __init led_drv_init(void)
{
	printk("a = %d\n",a);	
	int ret;
	printk("led模块加载成功\n");
	//0.创建全局的结构体对象
	led = kzalloc(sizeof(struct stm32mp157_led), GFP_KERNEL);
	if(!led)
	{
		printk("kzalloc error\n");
		return -ENOMEM;
	}
	
	//1.注册/申请设备号(高12=主设备号，哪一类设备，内核中唯一；低20=次设备号，该类设备中的哪一个，自己指定)
	//参数1：主设备号(如果传0，让内核自动分配一个未使用的设备号)
	//参数2：设备的描述，自己定义
	//参数3：设备操作函数集
	led->major = register_chrdev(0, "stm32mp157_led", &led_fops);
	if(led->major < 0)
	{
		ret = led->major;
		printk("register_chrdev error\n");
		goto kzalloc_err;
	}

	//2.创建类
	led->clazz = class_create(THIS_MODULE, "stm32mp157_led");
	if(IS_ERR(led->clazz))
	{
		ret = PTR_ERR(led->clazz);
		printk("class_create error\n");
		goto register_chrdev_err;
	}

    //3.创建设备节点
	//手动创建设备节点
	//mknod /dev/led_drv c 240 0
	//参数1: 类的指针
	//参数2: 父类
	//参数3: 设备号
	//参数4: 私有数据
	//参数5: 设备节点的名称
	led->dev = device_create(led->clazz, NULL, MKDEV(led->major, 0), NULL, "led_drv");
	if(IS_ERR(led->dev))
	{
		ret = PTR_ERR(led->dev);
		printk("device_create error\n");
		goto class_create_err;
	}

	//4.硬件初始化
	//虚拟地址映射
	led->rcc = ioremap(RCC, sizeof(rcc_t));
	if(!led->rcc)
	{
		ret = -ENOMEM;
		printk("ioremap_rcc error\n");
		goto device_create_err;
	}
	//开启锁相环
	led->rcc->PLL4CR |= (1 << 0);
	//判断PLL时钟是否稳定
	while(!(led->rcc->PLL4CR & (1 << 1)))
	{
	}
	//开启GPIOE和GPIOF时钟
	led->rcc->MP_AHB4ENSETR |= (1 << 4) | (1 << 5);

    //设置GPIOZ
	led->gpioz = ioremap(GPIOZ, sizeof(gpio_t));
	if(!led->gpioz)
	{
		ret = -ENOMEM;
		printk("ioremap_gpioz error\n");
		goto ioremap_rcc_err;
	}
	led->gpioz->MODER &= ~((0x03 << 10) | (0x03 << 12) | (0x03 << 14));
	if(!led->gpioz)
	{
		ret = -ENOMEM;
		printk("ioremap_gpioz error\n");
		goto ioremap_rcc_err;
	}
	led->gpioz->MODER &= ~((0x03 << 10) | (0x03 << 12) | (0x03 << 14));
	led->gpioz->MODER |= (0x01 << 10) | (0x01 << 12) | (0x01 << 14);
	led->gpioz->OTYPER &= ~((0x01 << 5) | (0x01 << 6) | (0x01 << 7));
	led->gpioz->OSPEEDR &= ~((0x03 << 10) | (0x03 << 12) | (0x03 << 14));
	led->gpioz->ODR &= ~((0x01 << 5) | (0x01 << 6) | (0x01 << 7));
	
	led->gpioe = ioremap(GPIOE, sizeof(gpio_t));
	if(!led->gpioe)
	{
		ret = -ENOMEM;
		printk("ioremap_gpioe error\n");
		goto ioremap_gpioz_err;
	}
	led->gpioe->MODER &= ~((0x03 << 16) | (0x03 << 20));
	led->gpioe->MODER |= (0x01 << 16) | (0x01 << 20);
	led->gpioe->OTYPER &= ~((0x01 << 8) | (0x01 << 10));
	led->gpioe->OSPEEDR &= ~((0x03 << 16) | (0x03 << 20));
	led->gpioe->ODR &= ~((0x01 << 8) | (0x01 << 10));

	led->gpiof = ioremap(GPIOF, sizeof(gpio_t));
	if(!led->gpiof)
	{
		ret = -ENOMEM;
		printk("ioremap_gpiof error\n");
		goto ioremap_gpiof_err;
	}
	led->gpioe->MODER &= ~(0x03 << 20);
	led->gpioe->MODER |= (0x01 << 20);
	led->gpioe->OTYPER &= ~(0x01 << 10);
	led->gpioe->OSPEEDR &= ~(0x03 << 20);
	led->gpioe->ODR &= ~(0x01 << 10);
	return 0;

	ioremap_gpiof_err:
		iounmap(led->gpioe);
	ioremap_gpioz_err:
		iounmap(led->gpioz);
	ioremap_rcc_err:
		iounmap(led->rcc);
	device_create_err:
		device_destroy(led->clazz, MKDEV(led->major, 0));
   	class_create_err:
		class_destroy(led->clazz);
	register_chrdev_err:
		unregister_chrdev(led->major, "stm32mp157_led");
	kzalloc_err:
		kfree(led);

	return ret;
}

static void __exit led_drv_exit(void)
{
	printk("led模块卸载成功\n");
	iounmap(led->gpiof);
	iounmap(led->gpioe);
	iounmap(led->gpioz);
	iounmap(led->rcc);
	device_destroy(led->clazz, MKDEV(led->major, 0));
	class_destroy(led->clazz);
